package com.globallogic.javatrainings.sergiiivanov.tests;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;

import org.junit.Before;
import org.junit.Test;

import com.globallogic.javatrainings.sergiiivanov.model.Course;
import com.globallogic.javatrainings.sergiiivanov.model.Lecture;
import com.globallogic.javatrainings.sergiiivanov.model.Lecture.LectureType;
import com.globallogic.javatrainings.sergiiivanov.model.Room;
import com.globallogic.javatrainings.sergiiivanov.model.Student;
import com.globallogic.javatrainings.sergiiivanov.model.UniversityWarning;
import com.globallogic.javatrainings.sergiiivanov.resources.ErrorCodes;
import com.globallogic.javatrainings.sergiiivanov.resources.Messages;

/**
 * <pre>
 * 32  5.    Lectures
 * 33  5.1.  Lecture has name, type, linked room
 * 34  5.2.  name should be unique within a course
 * 35  5.3.  linked room should have enough capacity for all enrolled students + teacher
 * 36  5.4.  Lectures could be added, removed and updated
 * 37  5.5.  Lectured list should be available
 * 38  5.6.  List of appointed rooms should be available
 * </pre>
 * 
 * @author Sergey
 * 
 */
public class LectureTest extends BasicTest {
    private final LectureType typeLECTURE = LectureType.LECTURE;
    private Course course;
    private Lecture lecture;

    @Before
    public void setupCourse() throws Exception {
        course = new Course();
        course.setName(nCourse1);
        course.setDiscipline(discipline1);
    }
    /**
     * 33  5.1.  Lecture has name, type, linked room
     * @throws Exception lecture name incorrect
     */
    @Before
    public void setupLecture() throws Exception {
        lecture = new Lecture();
        lecture.setName(nLec1);
        lecture.setType(lectureType1);
        lecture.setDescription(description1);
    }
    
    @Test
    public void testTypes() {
        String[] exp = {
                Messages.LECTURE_TYPE_LECTURE,
                Messages.LECTURE_TYPE_PRACTICE,
                Messages.LECTURE_TYPE_TEST,
                Messages.LECTURE_TYPE_EXAMINATION,
        };
        assertArrayEquals(exp, LectureType.getNamesList());
    }

    /**
     * Quick constructor still valid
     * @throws UniversityWarning
     */
    @Test
    public void quickLectureCreation() throws UniversityWarning {
        Lecture quickLecture = new Lecture(nLec1, typeLECTURE);
        assertEquals(nLec1, quickLecture.getName());
        assertEquals(typeLECTURE, quickLecture.getLectureType());
        try {
            quickLecture = new Lecture(empty, typeLECTURE);
            fail("Missed " + ErrorCodes.LECTURE_NAME_NULL);
        } catch (Exception e) {
            assertEquals(ErrorCodes.LECTURE_NAME_NULL, e.getMessage());
        }
        try {
            quickLecture = new Lecture(null, typeLECTURE);
            fail("Missed " + ErrorCodes.LECTURE_NAME_NULL);
        } catch (Exception e) {
            assertEquals(ErrorCodes.LECTURE_NAME_NULL, e.getMessage());
        }
    }

    /**
     * 34  5.2.  name should be unique within a course
     * @throws UniversityWarning
     */
    @Test
    public void testHaveDuplicates() throws UniversityWarning {
        course.addLecture(nLec1, typeLECTURE, empty);
        try {
            course.addLecture(nLec1, typeLECTURE, empty);
            fail("Missed " + ErrorCodes.LECTURE_NOT_UNIQUE);
        } catch (Exception e) {
            assertEquals(ErrorCodes.LECTURE_NOT_UNIQUE + nLec1, e.getMessage());
        }
    }

    /**
     *  no empty names
     */
    @Test
    public void setNameNotEmptyTest(){
        try {
            lecture.setName(empty);
            fail("Missed " + ErrorCodes.LECTURE_NAME_NULL);
        } catch (Exception e) {
            assertEquals(ErrorCodes.LECTURE_NAME_NULL, e.getMessage());
        }
        try {
            lecture.setName(null);
            fail("Missed " + ErrorCodes.LECTURE_NAME_NULL);
        } catch (Exception e) {
            assertEquals(ErrorCodes.LECTURE_NAME_NULL, e.getMessage());
        }
    }
    
    /**
     * 
     */
    
    /**
     * 35  5.3.  linked room should have enough capacity for all enrolled students + teacher
     * @throws UniversityWarning
     */
    @Test
    public void testRoomIsTooSmall() throws UniversityWarning {
        Room r = new Room(nRoom1);
        r.setToAuditorium();
        r.setCapacity(2);
        course.addLecture(nLec1, typeLECTURE, empty);
        course.addLecture(nLec2, typeLECTURE, empty);
        for (Lecture l2 : course.getLectures()) {
            l2.setRoom(r);
        }
        Student s1 = new Student(nPerson1, mobile, email);
        Student s2 = new Student(nPerson1, mobile, email);
        course.enrollStudent(s1);
        try {
            course.enrollStudent(s2);
            fail("Missed " + ErrorCodes.COURSE_NO_PLACES);
        } catch (Exception e) {
            assertEquals(ErrorCodes.COURSE_NO_PLACES, e.getMessage());
        }
        r.setCapacity(3);
        course.enrollStudent(s2);
        try {
            r.setCapacity(2);
            fail("Missed " + ErrorCodes.ROOM_IS_TOO_SMALL);
        } catch (Exception e) {
            assertEquals(ErrorCodes.ROOM_IS_TOO_SMALL, e.getMessage());
        }
    
        Room r2 = new Room("2");
        r2.setCapacity(2);
        r2.setToLaboratory();
        try {
            course.getLectureByIndex(0).setRoom(r2);
            fail("Missed " + ErrorCodes.ROOM_IS_TOO_SMALL);
        } catch (Exception e) {
            assertEquals(ErrorCodes.ROOM_IS_TOO_SMALL, e.getMessage());
        }
    }
    /**
     * 36  5.4.  Lectures could be added, removed and updated
     * @throws Exception
     */
    @Test
    public void addLectureTest() throws Exception {
        assertArrayEquals(new String[]{}, course.getLectures().toNamesList());
        course.addLecture(nLec1, typeLECTURE, empty);
        course.addLecture(nLec2, typeLECTURE, empty);
        assertArrayEquals(new String[]{nLec1, nLec2}, course.getLectures().toNamesList());
        course.removeLecture(course.getLectureByIndex(1));
        course.removeLecture(course.getLectureByIndex(0));
        assertArrayEquals(new String[]{}, course.getLectures().toNamesList());
    }
    
    /**
     * 36  5.4.  Lectures could be added, removed and updated
     * @throws Exception
     */
    @Test
    public void removeLectureTest() throws Exception {
        course.addLecture(nLec1, typeLECTURE, empty);
        course.addLecture(nLec2, typeLECTURE, empty);
        assertArrayEquals(new String[]{nLec1, nLec2}, course.getLectures().toNamesList());
        course.removeLecture(course.getLectureByIndex(1));
        try {
            course.removeLecture(course.getLectureByIndex(1));
            fail("Missed " + ErrorCodes.LECTURE_NOT_FOUND);
        } catch (Exception e) {
            assertEquals(ErrorCodes.LECTURE_NOT_FOUND, e.getMessage());
        }
        course.removeLecture(course.getLectureByIndex(0));
        try {
            course.removeLecture(course.getLectureByIndex(0));
            fail("Missed " + ErrorCodes.LECTURE_NOT_FOUND);
        } catch (Exception e) {
            assertEquals(ErrorCodes.LECTURE_NOT_FOUND, e.getMessage());
        }
        try {
            course.removeLecture(course.getLectureByIndex(-1));
            fail("Missed " + ErrorCodes.LECTURE_NOT_FOUND);
        } catch (Exception e) {
            assertEquals(ErrorCodes.LECTURE_NOT_FOUND, e.getMessage());
        }
        
    }
    
    /**
     * 36  5.4.  Lectures could be added, removed and updated
     */
    @Test
    public void UpdateLectureTest() throws Exception {
        lecture.setName(nLec2);
        lecture.setType(lectureType2);
        lecture.setDescription(description2);
        assertEquals(nLec2, lecture.getName());
        assertEquals(lectureType2, lecture.getLectureType());
        assertEquals(description2, lecture.getDescription());
        try {
            lecture.setName(null);
            fail("Missed " + ErrorCodes.LECTURE_NAME_NULL);
        } catch (Exception e) {
            assertEquals(ErrorCodes.LECTURE_NAME_NULL, e.getMessage());
        }
        lecture.setType(null);
        lecture.setDescription(null);
    }
    
    /**
     * 37  5.5.  Lectured list should be available
     */
    @Test
    public void getLecturesListTest() throws Exception {
        course.addLecture(nLec1, lectureType1, description1);
        course.addLecture(nLec2, lectureType2, description2);
        assertArrayEquals(new String[]{nLec1,nLec2}, course.getLectures().toNamesList());
    }
    
    /**
     * 38  5.6.  List of appointed rooms should be available
     */
    @Test
    public void appointedRoomsListTest() throws Exception {
        assertArrayEquals(new String[]{}, course.getAppointedRooms().toNamesList());
        course.addLecture(nLec1, typeLECTURE, description1);
        course.addLecture(nLec2, typeLECTURE, description2);
        Room r = new Room(nRoom1); r.setToAuditorium(); r.setCapacity(1);
        course.getLectureByIndex(0).setRoom(r);
        course.getLectureByIndex(1).setRoom(r);
        assertArrayEquals(new String[]{nRoom1}, course.getAppointedRooms().toNamesList());
    }
}
